﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Serialization;

namespace d39
{
    [Serializable]
    public class EffectInstance
    {
        [XmlIgnore]
        public EffectType Type { get; set; }

        [XmlIgnore]
        public Coordinate StartCorner { get; set; } // Used on all shapes

        [XmlAttribute("start-corner")]
        public string StartCornerString { get { return StartCorner.ToHumanReadableString(); } set { StartCorner = Coordinate.ParseHumanReadable(value); } }

        [XmlIgnore]
        public int? Radius { get; set; } // Used on Circle, Cone and Line

        [XmlAttribute("radius")]
        public string RadiusText { get { return Radius == null ? null : Radius.ToString(); } set { Radius = string.IsNullOrEmpty(value) ? (int?)null : int.Parse(value); } }

        [XmlIgnore]
        public Vector? Direction { get; set; } // Used on Cone and Line

        [XmlAttribute("direction")]
        public string DirectionString { get { return Direction == null ? null : Direction.Value.ToHumanReadableMoveString(); } set { if (value != null) Direction = Moves.ParseHumanReadable(value); } }

        [XmlIgnore] // Used on Rectangle
        public int? ExtentEast { get; set; }

        [XmlIgnore] // Used on Rectangle
        public int? ExtentWest { get; set; }

        [XmlIgnore] // Used on Rectangle
        public int? ExtentNorth { get; set; }

        [XmlIgnore] // Used on Rectangle
        public int? ExtentSouth { get; set; }

        [XmlAttribute("extent-east")]
        public string ExtentEastText { get { return ExtentEast == null ? null : ExtentEast.ToString(); } set { ExtentEast = string.IsNullOrEmpty(value) ? (int?)null : int.Parse(value); } }
        [XmlAttribute("extent-west")]
        public string ExtentWestText { get { return ExtentWest == null ? null : ExtentEast.ToString(); } set { ExtentWest = string.IsNullOrEmpty(value) ? (int?)null : int.Parse(value); } }
        [XmlAttribute("extent-north")]
        public string ExtentNorthText { get { return ExtentNorth == null ? null : ExtentEast.ToString(); } set { ExtentNorth = string.IsNullOrEmpty(value) ? (int?)null : int.Parse(value); } }
        [XmlAttribute("extent-south")]
        public string ExtentSouthText { get { return ExtentSouth == null ? null : ExtentEast.ToString(); } set { ExtentSouth = string.IsNullOrEmpty(value) ? (int?)null : int.Parse(value); } }

        // The format is:
        // xyrDNESW
        // xy = start corner coordinate
        // r = radius (in base26 format), only if shape is circle (hollow or filled), cone or line
        // D = direction, NnEeWwSs format, only if shape is cone or line
        // NESW = north, east, south, west, in base26 format, only if shape is rectangle (hollow or filled)
        public static EffectInstance Parse(EffectType type, string str, int start, out int end)
        {
            var shape = type.Shape;
            end = start;
            var startCorner = Coordinate.Parse(str, end, out end);
            int? radius = null;
            if (shape.HasRadius()) radius = Base26.ParseInt(str, end, out end);
            Vector? direction = null;
            if (shape.HasDirection()) direction = Moves.FromMoveChar(str[end++]);
            int? north = null;
            int? east = null;
            int? south = null;
            int? west = null;
            if (shape.HasExtents())
            {
                north = Base26.ParseInt(str, end, out end);
                east = Base26.ParseInt(str, end, out end);
                south = Base26.ParseInt(str, end, out end);
                west = Base26.ParseInt(str, end, out end);
            }
            return new EffectInstance()
            {
                Type = type,
                StartCorner = startCorner,
                Radius = radius,
                Direction = direction,
                ExtentNorth = north,
                ExtentEast = east,
                ExtentSouth = south,
                ExtentWest = west,
            };
        }
        public override string ToString()
        {
            var str = StartCorner.ToString();
            if (Radius != null) str += Base26.IntToString((int)Radius);
            if (Direction != null) str += ((Vector)Direction).ToMoveChar();
            if (ExtentNorth != null) str += Base26.IntToString((int)ExtentNorth);
            if (ExtentEast != null) str += Base26.IntToString((int)ExtentEast);
            if (ExtentSouth != null) str += Base26.IntToString((int)ExtentSouth);
            if (ExtentWest != null) str += Base26.IntToString((int)ExtentWest);
            return str;
        }

        public IEnumerable<Coordinate> Points
        {
            get
            {
                switch (Type.Shape)
                {

                    case EffectShape.HollowCircle:

                        return EffectShapes.HollowCircle(StartCorner, Radius ?? 1);

                    case EffectShape.FilledCircle:

                        return EffectShapes.FilledCircle(StartCorner, Radius ?? 1);

                    case EffectShape.Cone:

                        return EffectShapes.Cone(StartCorner, (Vector)Direction, Radius ?? 1);

                    case EffectShape.Line:

                        return EffectShapes.Line(StartCorner, (Vector)Direction, Radius ?? 1);

                    case EffectShape.HollowRectangle:

                        return EffectShapes.HollowRectangle(StartCorner, ExtentNorth ?? 1, ExtentEast ?? 1, ExtentSouth ?? 1, ExtentWest ?? 1);

                    case EffectShape.FilledRectangle:

                        return EffectShapes.FilledRectangle(StartCorner, ExtentNorth ?? 1, ExtentEast ?? 1, ExtentSouth ?? 1, ExtentWest ?? 1);

                    default: throw new ApplicationException("Invalid shape");
                }
            }
        }
    }
}